module Extras
    where

import ExprDataTypes

--extraStackValues = [("int","viaux",10),("double","vdaux",11), ("bool","vbaux",12)]
extraStackValues =[]

mLabel t a = [((LABEL t a),0)]
mNop = [(NOP,0)]
mUjp t a = [((UJP t a),0)]
mCjp t a = [((CJP t a),0)]
mFcjp t a = [((FCJP t a),0)]
mAdd = [(ADD,(-1))]
mSub = [(SUB,(-1))]
mMult = [(MULT,(-1))]
mDiv = [(DIV,(-1))]
mEq = [(EQ6,(-1))]
mLt = [(LT6,(-1))]
mGt = [(GT6,(-1))]
mAnd = [(AND,(-1))]
mNot = [(NOT,(0))]
mOr = [(OR,(-1))]
mPushG c t = pushG c t
mPush n = [(PUSH n,1)]
mPushS a = [(PUSHS a,1)]
mPushD a = [(PUSHD a,1)]
mPushT = [(PUSHT,1)]
mPushF = [(PUSHF,1)]
mFetch a vs = [(FETCH (buscVar vs a),(1))]
mFetchCoe a vs mt lqedm = [(FETCHCOE (buscVar vs a) mt lqedm,(1))]
mDup = [(DUP,1)]
mStore a vs = [(STORE (buscVar vs a),(-1))]
mWrite a vs = [(WRITE (buscVarTipo vs a),-1)]
mRead = [(READ,1)]
mLength a vs = [(LENGTH (buscVarTipo vs a),1)]
mPop = [(POP,-1)]

buscVar :: VarMap -> String -> Integer
buscVar [] _ = 0
buscVar ((tipo,var,pos):xs) nombre 
	|var==nombre = pos
	|otherwise = buscVar xs nombre
	
buscVarTipo :: VarMap -> String -> String
buscVarTipo [] _ = ""
buscVarTipo ((tipo,var,pos):xs) nombre 
	|var==nombre = tipo
	|otherwise = buscVarTipo xs nombre	

buscVarTipoPorInt :: VarMap -> Integer -> String
buscVarTipoPorInt [] _ = ""
buscVarTipoPorInt ((tipo,var,pos):xs) num
	|num == pos = tipo
	|otherwise = buscVarTipoPorInt xs num

cambioPush ((PUSH n), a) = (PUSHD (fromInteger n),a)
cambioPush a = a

cambioStore :: [(TInstruccionAM,Integer)] -> VarMap ->[(TInstruccionAM,Integer)]
cambioStore [] _ = [] 
cambioStore (((STORE n),a):xs) vs 
    | (buscVarTipoPorInt vs n) == "int" = [(CONV,0)] ++ [((STORE n),a)] ++ cambioStore xs vs 
    | otherwise = [((STORE  n),a)] ++ cambioStore xs vs 
cambioStore (x:xs) vs = [x] ++ cambioStore xs vs

cambioFetch :: [(TInstruccionAM,Integer)] -> VarMap ->[(TInstruccionAM,Integer)]
cambioFetch [] _ = [] 
cambioFetch (((FETCH n),a):xs) vs 
    | (buscVarTipoPorInt vs n) == "int" = [((FETCH n),a)] ++ [((CONVD),0)] ++ cambioFetch xs vs 
    | otherwise = [((FETCH  n),a)] ++ cambioFetch xs vs 
cambioFetch (x:xs) vs = [x] ++ cambioFetch xs vs

--nuevaFuncion::[(TInstruccionAM,Integer)] -> VarMap -> [(TInstruccionAM,Integer)]
nuevaFuncion insts vs = cambioFetch (cambioStore (map cambioPush insts) vs) vs

limpiaC :: [Char] -> String
limpiaC [] = ""
limpiaC  str = reverse(tail(reverse(tail str)))
-- TODO: crear variables de mSTORE !!!
codCoercion :: Tipo -> Tipo -> VarMap -> [(TInstruccionAM,Integer)]
codCoercion mt lqedm vs = 
    case lqedm of 
        "string" -> case mt of 
            "string" -> [] 
            "int" -> mStore "viaux" vs ++ mFetchCoe "viaux" vs mt lqedm 
            "double" -> mStore "vdaux" vs ++ mFetchCoe "vdaux" vs mt lqedm 
            "bool" -> mStore "vbaux" vs ++ mFetchCoe "vbaux" vs mt lqedm 
            "" -> []
        "double" -> case mt of 
            "" -> []
            "double" -> [] 
        "int" -> [(CONVD,0)] 
        "bool" -> []
        "" -> []


pushG :: Combo -> String -> [(TInstruccionAM,Integer)]
pushG (NumInt a) t = case t of 
                        "string" -> mPushS (show a) 
                        "double" -> mPushD (fromInteger a)
                        _  -> mPush a
pushG (NumDouble a) t = case t of "string" -> mPushS (show a)
                                  _ -> mPushD a
pushG (BTrue) t = case t of "string" -> mPushS "true"
                            _  -> mPushT
pushG (BFalse) t = case t of "string" -> mPushS "false"
                             _ -> mPushF
pushG (Lit a) t = mPushS (limpiaC a)


getDefaultValue a 
    | a == "int" = mPush 0
    | a == "double" = mPushD 0
    | a == "bool" = mPushF 
    | otherwise = mPushS ""
